package com.wangijun.yuan.web.service;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.wangijun.yuan.web.base.CommonPage;
import com.wangijun.yuan.core.base.YesNoEnum;
import com.wangijun.yuan.core.domain.*;
import com.wangijun.yuan.core.model.em.NoticeTypeEnum;
import com.wangijun.yuan.web.api.NoticeController;
import com.wangijun.yuan.web.mapper.NoticeInfoMapper;
import com.wangijun.yuan.web.model.dto.NoticeQryParam;
import com.wangijun.yuan.web.model.vo.NoticeCountVO;
import com.wangijun.yuan.web.model.vo.NoticeInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class NoticeService extends ServiceImpl<NoticeInfoMapper, NoticeInfo> {
    private final OperateInfoService operateInfoService;
    private final ArticleService articleService;
    private final CommentService commentService;
    private final UserService userService;

    public void pushArt(Long artId) {
        // 获取关注这个人ID的用户，
        Article article = Db.getById(artId, Article.class);
        List<Long> fansUserIds = operateInfoService.getFansUserIds(article.getCreateBy());
        for (Long userId : fansUserIds) {
            Db.save(
                    NoticeInfo.builder()
                            .receiveUserId(userId)
                            .createUserId(article.getCreateBy())
                            .createTime(LocalDateTime.now())
                            .year(DateUtil.year(DateUtil.date()))
                            .artId(artId)
                            .noticeType(NoticeTypeEnum.pushArt)
                            .build()
            );
        }
    }

    public void editArt(Long artId) {
        Article article = Db.getById(artId, Article.class);
        List<Long> fansUserIds = SpringUtil.getBean(OperateInfoService.class).getFansUserIds(article.getCreateBy());
        for (Long userId : fansUserIds) {
            Db.save(
                    NoticeInfo.builder()
                            .receiveUserId(userId)
                            .createUserId(article.getCreateBy())
                            .createTime(LocalDateTime.now())
                            .year(DateUtil.year(DateUtil.date()))
                            .artId(artId)
                            .noticeType(NoticeTypeEnum.editArt)
                            .build()
            );
        }
    }

    public void likedArt(Long userId, Long dataId) {
        Article article = Db.getById(dataId, Article.class);
        Db.save(
                NoticeInfo.builder()
                        .receiveUserId(article.getCreateBy())
                        .createUserId(userId)
                        .createTime(LocalDateTime.now())
                        .year(DateUtil.year(DateUtil.date()))
                        .noticeType(NoticeTypeEnum.likedArt)
                        .artId(dataId)
                        .build()
        );
    }

    public void favArt(Long userId, Long dataId) {
        Article article = Db.getById(dataId, Article.class);
        Db.save(
                NoticeInfo.builder()
                        .receiveUserId(article.getCreateBy())
                        .createUserId(userId)
                        .createTime(LocalDateTime.now())
                        .year(DateUtil.year(DateUtil.date()))
                        .noticeType(NoticeTypeEnum.favArt)
                        .artId(dataId)
                        .build()
        );
    }

    public void likedComment(Long userId, Long dataId) {
        // 大于零说明是点赞
        Comment comment = Db.getById(dataId, Comment.class);
        Db.save(
                NoticeInfo.builder()
                        .receiveUserId(comment.getUserId())
                        .createUserId(userId)
                        .createTime(LocalDateTime.now())
                        .year(DateUtil.year(DateUtil.date()))
                        .noticeType(NoticeTypeEnum.likedComment)
                        .artId(comment.getArticleId())
                        .commentId(comment.getId())
                        .build()
        );
    }

    public void followUser(Long userId, Long dataId) {
        Db.save(
                NoticeInfo.builder()
                        .receiveUserId(dataId)
                        .createUserId(userId)
                        .createTime(LocalDateTime.now())
                        .year(DateUtil.year(DateUtil.date()))
                        .noticeType(NoticeTypeEnum.followUser)
                        .build()
        );
    }

    @SaCheckLogin
    public CommonPage<NoticeInfoVO> noticeArt(NoticeQryParam param) {
        Page<NoticeInfo> page = this.lambdaQuery()
                .eq(NoticeInfo::getReceiveUserId, StpUtil.getLoginIdAsLong())
                .orderByAsc(NoticeInfo::getNoticeFlag)
                .orderByDesc(NoticeInfo::getCreateTime)
                .in(NoticeInfo::getNoticeType,
                        List.of(
                                NoticeTypeEnum.pushArt.getCode(),
                                NoticeTypeEnum.editArt.getCode()
                        ))
                .page(param.page());
        return getNoticeInfoVOCommonPage(page);
    }

    public CommonPage<NoticeInfoVO> noticePeople(NoticeQryParam param) {
        Page<NoticeInfo> page = this.lambdaQuery()
                .eq(NoticeInfo::getReceiveUserId, StpUtil.getLoginIdAsLong())
                .orderByAsc(NoticeInfo::getNoticeFlag)
                .orderByDesc(NoticeInfo::getCreateTime)
                .in(NoticeInfo::getNoticeType,
                        List.of(
                                NoticeTypeEnum.followUser.getCode()
                        ))
                .page(param.page());
        return getNoticeInfoVOCommonPage(page);
    }

    public CommonPage<NoticeInfoVO> noticeFavorite(NoticeQryParam param) {
        Page<NoticeInfo> page = this.lambdaQuery()
                .eq(NoticeInfo::getReceiveUserId, StpUtil.getLoginIdAsLong())
                .orderByAsc(NoticeInfo::getNoticeFlag)
                .orderByDesc(NoticeInfo::getCreateTime)
                .in(NoticeInfo::getNoticeType,
                        List.of(
                                NoticeTypeEnum.likedArt.getCode(),
                                NoticeTypeEnum.favArt.getCode(),
                                NoticeTypeEnum.likedComment.getCode(),
                                NoticeTypeEnum.replayComment.getCode()
                        ))
                .page(param.page());
        return getNoticeInfoVOCommonPage(page);
    }

    public Boolean noticeFlag(NoticeController.FlagParam param) {
        switch (param.tab()) {
            case art -> {
                getBaseMapper().updateFlag(
                        StpUtil.getLoginIdAsLong(),
                        List.of(
                                NoticeTypeEnum.pushArt.getCode(),
                                NoticeTypeEnum.editArt.getCode()
                        )
                );
            }
            case people -> {
                getBaseMapper().updateFlag(
                        StpUtil.getLoginIdAsLong(),
                        List.of(
                                NoticeTypeEnum.followUser.getCode()
                        )
                );

            }
            case favorite -> {
                getBaseMapper().updateFlag(
                        StpUtil.getLoginIdAsLong(),
                        List.of(
                                NoticeTypeEnum.likedArt.getCode(),
                                NoticeTypeEnum.favArt.getCode(),
                                NoticeTypeEnum.likedComment.getCode(),
                                NoticeTypeEnum.replayComment.getCode()
                        )
                );
            }
        }
        return true;
    }

    public NoticeCountVO noticeTag() {
        List<NoticeInfo> list = this.lambdaQuery()
                .eq(NoticeInfo::getReceiveUserId, StpUtil.getLoginIdAsLong())
                .eq(NoticeInfo::getNoticeFlag, YesNoEnum.NO.getCode())
                .list();

        HashMap<Integer, String> map = new HashMap<>();

        for (NoticeTypeEnum typeEnum : NoticeTypeEnum.values()) {
            map.put(typeEnum.getCode(), typeEnum.getMessage());
        }

        UserSetting setting = Db.lambdaQuery(UserSetting.class)
                .eq(UserSetting::getUserId, StpUtil.getLoginIdAsLong())
                .one();

        return new NoticeCountVO(
                list.stream().anyMatch(i -> List.of(
                        NoticeTypeEnum.pushArt,
                        NoticeTypeEnum.editArt
                ).contains(i.getNoticeType())),

                list.stream().anyMatch(i -> List.of(
                        NoticeTypeEnum.followUser
                ).contains(i.getNoticeType())),

                list.stream().anyMatch(i -> List.of(
                        NoticeTypeEnum.likedComment,
                        NoticeTypeEnum.likedArt,
                        NoticeTypeEnum.favArt,
                        NoticeTypeEnum.replayComment
                ).contains(i.getNoticeType())),
                map,
                setting.getHideRed()
        );
    }

    public CommonPage<NoticeInfoVO> noticeList(NoticeQryParam param) {
        LambdaQueryChainWrapper<NoticeInfo> wrapper = this.lambdaQuery()
                .eq(NoticeInfo::getReceiveUserId, StpUtil.getLoginIdAsLong())
                .orderByAsc(NoticeInfo::getNoticeFlag)
                .orderByDesc(NoticeInfo::getCreateTime);
        if (param.getType() != null) {
            if (param.getType() != -1) {
                wrapper.eq(NoticeInfo::getNoticeType, param.getType());
            }
        }
        Page<NoticeInfo> page = wrapper.page(param.page());
        return getNoticeInfoVOCommonPage(page);
    }

    /**
     * 功能描述: 补全VO
     *
     * @author wlf 2024/8/12 9:48
     */
    private CommonPage<NoticeInfoVO> getNoticeInfoVOCommonPage(Page<NoticeInfo> page) {
        return CommonPage.toPage(page, NoticeInfoVO.class, (vo) -> {
            vo.setNoticeTime(LocalDateTimeUtil.format(vo.getCreateTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            vo.setCreateUserInfo(userService.getBaseUser(vo.getCreateUserId()));
            if (vo.getArtId() != null) {
                vo.setArticleTitle(articleService.getById(vo.getArtId()).getTitle());
            }
            if (vo.getCommentId() != null) {
                vo.setComment(commentService.getById(vo.getCommentId()).getContent());
            }
        });
    }
}
